﻿#pragma once
/// Copyright 2012, Alex Averian, Yonan Research
/// Released under BSD Licence


#include <comdef.h>
#include <shlwapi.h> ///QISearch



#ifndef RINOK
#define RINOK(x)  { HRESULT __result = (x); if (__result != S_OK) return __result; }
#define RINOK2(x) { HRESULT __result = (x); if (__result != S_OK) return false; }
#endif





namespace micro
{
namespace com
{

// This error code is not defined in the Windows headers so we define it here for readibility.
//const static HRESULT E_USER_CANCELED_OPERATION = 0x800704C7;



template <class T>
HRESULT SetInterface( T ** ppT, IUnknown * punk )
{
    SafeRelease( ppT );
    return punk ? punk->QueryInterface( ppT ) : E_NOINTERFACE;
}

template <class T>
void SafeRelease( T ** ppT )
{
    if ( *ppT )
    {
        ( *ppT )->Release();
        *ppT = nullptr;
    }
}

class QComInitializer
{
public:
    QComInitializer()
    {
        HRESULT err = ::CoInitialize ( nullptr );

        if ( err != S_OK )
            throw L"Couldn't initialize COM";
    }
    ~QComInitializer ()
    {
        ::CoUninitialize ();
    }
};


class QOleInitializer
{
public:
    QOleInitializer()
    {
        HRESULT hr = ::OleInitialize( nullptr );

        if ( FAILED ( hr ) )
            throw QError();
    }
    ~QOleInitializer ()
    {
        ::OleFlushClipboard ();
        ::OleUninitialize ();
    }
};


template <class T>
class QComPointer
{
//protected:
    T * p;
public:
    // typedef T _PtrClass;
    QComPointer()
    {
        p = nullptr;
    }
    QComPointer( T * p0 )
    {
        if ( ( p = p0 ) != nullptr )
            p->AddRef();
    }

    QComPointer(  IUnknown * lp )
    {
        if ( lp != nullptr )
            lp->QueryInterface( __uuidof( T ), ( void ** ) &p );
    }

    QComPointer( const QComPointer<T> & lp )
    {
        if ( ( p = lp.p ) != nullptr )
            p->AddRef();
    }
    ~QComPointer()
    {
        if ( p )
            p->Release();
    }
    void Release()
    {
        if ( p )
        {
            p->Release();
            p = nullptr;
        }
    }
    operator T * () const
    {
        return ( T * )p;
    }



    // T& operator*() const {  return *p; }
    T ** operator&()
    {
        return &p;
    }
    T * operator->() const
    {
        return p;
    }
    T * operator=( T * p0 )
    {
        if ( p0 )
            p0->AddRef();

        if ( p )
            p->Release();

        p = p0;
        return p0;
    }


    T * operator=( const QComPointer<T> & lp )
    {
        return ( *this = lp.p );
    }
    bool operator!() const
    {
        return ( p == nullptr );
    }
    // bool operator==(T* pT) const {  return p == pT; }
    // Compare two objects for equivalence



    void Attach( T * p2 )
    {
        Release();
        p = p2;
    }
    T * Detach()
    {
        T * pt = p;
        p = nullptr;
        return pt;
    }


    template <class Q>
    HRESULT QueryInterface( REFGUID iid, Q ** pp ) const
    {
        return p->QueryInterface( iid, ( void ** )pp );
    }


    HRESULT CoCreateInstance(	REFCLSID rclsid = __uuidof( T ), LPUNKNOWN pUnkOuter = nullptr, DWORD dwClsContext = CLSCTX_INPROC_SERVER )
    {
        ASSERT( p == nullptr );
        return ::CoCreateInstance( rclsid, pUnkOuter,	dwClsContext, __uuidof( T ),  ( LPVOID * ) & p );
    }
};




class QUnknown: virtual IUnknown
{
    ULONG		m_RefCount;

public:
    QUnknown(): m_RefCount( 0 ) {}

    virtual HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, void  * * ppv )
    {
        if ( !ppv )
            return E_POINTER;

        *ppv = nullptr;


        static const QITAB qit[] =
        {
            QITABENT( QUnknown, IUnknown ),
            { 0 },
        };


        return QISearch( this, qit, riid, ppv );
    }


    STDMETHOD_( ULONG, AddRef )()
    {
        return ++ m_RefCount;
    }
    STDMETHOD_( ULONG, Release )()
    {
        if ( -- m_RefCount != 0 )
            return m_RefCount;

        delete this;

        return 0;
    }

    /*STDMETHOD_(ULONG, AddRef)() { InterlockedIncrement(&m_RefCount); return m_RefCount; }
    STDMETHOD_(ULONG, Release)()
    {
    	InterlockedDecrement( &m_RefCount);
    	if (m_RefCount != 0) return m_RefCount;
    	delete this; return 0;
    }*/
};


typedef _variant_t	QVariant;
typedef _bstr_t		QBSTR;




// String allocated by CoTaskMemAlloc
class QComString
{
public:
    LPWSTR m_pstr;

    QComString() : m_pstr( NULL )
    {
    }

    QComString( LPCWSTR pstrText ) : m_pstr( NULL )
    {
        if ( pstrText == NULL )
            return;

        size_t len =  wcslen( pstrText );
        m_pstr = ( LPWSTR ) ::CoTaskMemAlloc( ( 1 + len ) * sizeof( WCHAR ) );

        if ( m_pstr != NULL )
            _tcscpy_s( m_pstr, len + 1, pstrText );
    }

    ~QComString()
    {
        if ( m_pstr != NULL )
            ::CoTaskMemFree( m_pstr );
    }

    void Attach( LPWSTR pstr )
    {
        if ( m_pstr != NULL )
            ::CoTaskMemFree( m_pstr );

        m_pstr = pstr;
    }

    LPWSTR Detach()
    {
        LPWSTR pstr = m_pstr;
        m_pstr = NULL;
        return pstr;
    }

    bool IsEmpty() const
    {
        return m_pstr == NULL || m_pstr[0] == '\0';
    }

    operator LPWSTR() const
    {
        return m_pstr == NULL ? L"" : m_pstr;
    }

    LPWSTR * operator&()
    {
        ASSERT( m_pstr == NULL );
        return &m_pstr;
    }
};





// class QVariant : public _variant_t
// {
//
// };
// class QBSTR : public _bstr_t
// {
//
// };

//
// class QBstr
// {
// public:
//     BSTR m_str;
//
//     QBstr() throw()
//     {
//         m_str = NULL;
//     }
//     QBstr( decltype( __nullptr ) ) throw()
//     {
//         m_str = NULL;
//     }
// #ifdef _ATL_CCOMBSTR_EXPLICIT_CONSTRUCTORS
//     explicit QBstr( _In_ int nSize )
// #else
//     QBstr( _In_ int nSize )
// #endif
//     {
//         if ( nSize < 0 )
//         {
//             throw( E_INVALIDARG );
//         }
//
//         if ( nSize == 0 )
//         {
//             m_str = NULL;
//         }
//         else
//         {
//             m_str = ::SysAllocStringLen( NULL, nSize );
//
//             if ( !*this )
//             {
//                 throw( E_OUTOFMEMORY );
//             }
//         }
//     }
//
//     QBstr( _In_ int nSize, _In_reads_opt_( nSize ) LPCOLESTR sz )
//     {
//         if ( nSize < 0 )
//         {
//             throw( E_INVALIDARG );
//         }
//
//         if ( nSize == 0 )
//         {
//             m_str = NULL;
//         }
//         else
//         {
//             m_str = ::SysAllocStringLen( sz, nSize );
//
//             if ( !*this )
//             {
//                 throw( E_OUTOFMEMORY );
//             }
//         }
//     }
//
//     QBstr( _In_opt_z_ LPCOLESTR pSrc )
//     {
//         if ( pSrc == NULL )
//         {
//             m_str = NULL;
//         }
//         else
//         {
//             m_str = ::SysAllocString( pSrc );
//
//             if ( !*this )
//             {
//                 throw( E_OUTOFMEMORY );
//             }
//         }
//     }
//
//     QBstr( _In_ const QBstr & src )
//     {
//         m_str = src.Copy();
//
//         if ( !!src && !*this )
//         {
//             throw( E_OUTOFMEMORY );
//         }
//     }
//
//     QBstr( _In_ REFGUID guid )
//     {
//         OLECHAR szGUID[64];
//         ::StringFromGUID2( guid, szGUID, 64 );
//         m_str = ::SysAllocString( szGUID );
//
//         if ( !*this )
//         {
//             throw( E_OUTOFMEMORY );
//         }
//     }
//
//     QBstr & operator=( decltype( __nullptr ) ) throw()
//     {
//         ::SysFreeString( m_str );
//         m_str = NULL;
//         return *this;
//     }
//
//     QBstr & operator=( _In_ const QBstr & src )
//     {
//         if ( m_str != src.m_str )
//         {
//             ::SysFreeString( m_str );
//             m_str = src.Copy();
//
//             if ( !!src && !*this )
//             {
//                 throw( E_OUTOFMEMORY );
//             }
//         }
//
//         return *this;
//     }
//
//     QBstr & operator=( _In_opt_z_ LPCOLESTR pSrc )
//     {
//         if ( pSrc != m_str )
//         {
//             ::SysFreeString( m_str );
//
//             if ( pSrc != NULL )
//             {
//                 m_str = ::SysAllocString( pSrc );
//
//                 if ( !*this )
//                 {
//                     throw( E_OUTOFMEMORY );
//                 }
//             }
//             else
//             {
//                 m_str = NULL;
//             }
//         }
//
//         return *this;
//     }
//     QBstr( _Inout_ QBstr && src )
//     {
//         m_str = src.m_str;
//         src.m_str = NULL;
//     }
//
//     QBstr & operator=( _Inout_ QBstr && src )
//     {
//         if ( m_str != src.m_str )
//         {
//             ::SysFreeString( m_str );
//             m_str = src.m_str;
//             src.m_str = NULL;
//         }
//
//         return *this;
//     }
//
//     ~QBstr() throw();
//
//     unsigned int Length() const throw()
//     {
//         return ::SysStringLen( m_str );
//     }
//
//     unsigned int ByteLength() const throw()
//     {
//         return ::SysStringByteLen( m_str );
//     }
//
//     operator BSTR() const throw()
//     {
//         return m_str;
//     }
//
//
//     BSTR * operator&() throw()
//     {
//
//         return &m_str;
//     }
//
//     BSTR Copy() const throw()
//     {
//         if ( !*this )
//         {
//             return NULL;
//         }
//         else
//             if ( m_str != NULL )
//             {
//                 return ::SysAllocStringByteLen( ( char * )m_str, ::SysStringByteLen( m_str ) );
//             }
//             else
//             {
//                 return ::SysAllocStringByteLen( NULL, 0 );
//             }
//     }
//
//     _Check_return_ HRESULT CopyTo( _Outptr_result_maybenull_ _Result_nullonfailure_ BSTR * pbstr ) const throw()
//     {
//         ASSERT( pbstr != NULL );
//
//         if ( pbstr == NULL )
//         {
//             return E_POINTER;
//         }
//
//         *pbstr = Copy();
//
//         if ( ( *pbstr == NULL ) && ( m_str != NULL ) )
//         {
//             return E_OUTOFMEMORY;
//         }
//
//         return S_OK;
//     }
//
//     // copy BSTR to VARIANT
//     _Check_return_ HRESULT CopyTo( _Out_ VARIANT * pvarDest ) const throw()
//     {
//         ASSERT( pvarDest != NULL );
//         HRESULT hRes = E_POINTER;
//
//         if ( pvarDest != NULL )
//         {
//             pvarDest->vt = VT_BSTR;
//             pvarDest->bstrVal = Copy();
//
//             if ( pvarDest->bstrVal == NULL && m_str != NULL )
//             {
//                 hRes = E_OUTOFMEMORY;
//             }
//             else
//             {
//                 hRes = S_OK;
//             }
//         }
//
//         return hRes;
//     }
//
//     void Attach( _In_opt_z_ BSTR src ) throw()
//     {
//         if ( m_str != src )
//         {
//             ::SysFreeString( m_str );
//             m_str = src;
//         }
//     }
//
//     _Ret_maybenull_z_ BSTR Detach() throw()
//     {
//         BSTR s = m_str;
//         m_str = NULL;
//         return s;
//     }
//
//     void Empty() throw()
//     {
//         ::SysFreeString( m_str );
//         m_str = NULL;
//     }
//
//     bool operator!() const throw()
//     {
//         return ( m_str == NULL );
//     }
//
//     _Check_return_ HRESULT Append( _In_ const QBstr & bstrSrc ) throw()
//     {
//         return AppendBSTR( bstrSrc.m_str );
//     }
//
// //     _Check_return_ HRESULT Append( _In_z_ LPCOLESTR lpsz ) throw()
// //     {
// //         return Append( lpsz, UINT( ocslen( lpsz ) ) );
// //     }
//
//     // a BSTR is just a LPCOLESTR so we need a special version to signify
//     // that we are appending a BSTR
//     _Check_return_ HRESULT AppendBSTR( _In_opt_z_ BSTR p ) throw()
//     {
//         if ( ::SysStringLen( p ) == 0 )
//         {
//             return S_OK;
//         }
//
//         BSTR bstrNew = NULL;
//         HRESULT hr;
//         _Analysis_assume_( p );
//         hr = VarBstrCat( m_str, p, &bstrNew );
//
//         if ( SUCCEEDED( hr ) )
//         {
//             ::SysFreeString( m_str );
//             m_str = bstrNew;
//         }
//
//         return hr;
//     }
//
//     _Check_return_ HRESULT Append( _In_reads_opt_( nLen ) LPCOLESTR lpsz, _In_ int nLen ) throw()
//     {
//         if ( lpsz == NULL || ( m_str != NULL && nLen == 0 ) )
//         {
//             return S_OK;
//         }
//         else
//             if ( nLen < 0 )
//             {
//                 return E_INVALIDARG;
//             }
//
//         const unsigned int n1 = Length();
//         unsigned int n1Bytes = 0;
//         unsigned int nSize = 0;
//         unsigned int nSizeBytes = 0;
//
//         HRESULT hr = S_OK;
//         nSize =  n1 +  nLen ;
//
//         nSizeBytes = nSize * sizeof( OLECHAR ) ;
//
//         n1Bytes = n1 * sizeof( OLECHAR );
//
//
//
//         BSTR b = ::SysAllocStringLen( NULL, nSize );
//
//         if ( b == NULL )
//         {
//             return E_OUTOFMEMORY;
//         }
//
//         if ( ::SysStringLen( m_str ) > 0 )
//         {
//             // _Analysis_assume_( m_str ); // ::SysStringLen(m_str) guarantees that m_str != NULL
//             memcpy_s( b, nSizeBytes, m_str, n1Bytes );
//         }
//
//         memcpy_s( b + n1, nLen * sizeof( OLECHAR ), lpsz, nLen * sizeof( OLECHAR ) );
//         b[nSize] = '\0';
//         SysFreeString( m_str );
//         m_str = b;
//         return S_OK;
//     }
//
//
//     _Check_return_ HRESULT Append( _In_ char ch ) throw()
//     {
//         OLECHAR chO = ch;
//
//         return( Append( &chO, 1 ) );
//     }
//
//     _Check_return_ HRESULT Append( _In_ wchar_t ch ) throw()
//     {
//         return( Append( &ch, 1 ) );
//     }
//
//     _Check_return_ HRESULT AppendBytes(
//         _In_reads_opt_( nLen ) const char * lpsz,
//         _In_ int nLen ) throw()
//     {
//         if ( lpsz == NULL || nLen == 0 )
//         {
//             return S_OK;
//         }
//         else
//             if ( nLen < 0 )
//             {
//                 return E_INVALIDARG;
//             }
//
//         const unsigned int n1 = ByteLength();
//         unsigned int nSize = 0;
//         nSize =  n1 *  nLen;
//
//
//
//         BSTR b = ::SysAllocStringByteLen( NULL, nSize );
//
//         if ( b == NULL )
//         {
//             return E_OUTOFMEMORY;
//         }
//
//         memcpy_s( b, nSize, m_str, n1 );
//         memcpy_s( ( ( char * )b ) + n1, nLen, lpsz, nLen );
//
//         *( ( OLECHAR * )( ( ( char * )b ) + nSize ) ) = '\0';
//         SysFreeString( m_str );
//         m_str = b;
//         return S_OK;
//     }
//
//     _Check_return_ HRESULT AssignBSTR( _In_opt_z_ const BSTR bstrSrc ) throw()
//     {
//         HRESULT hr = S_OK;
//
//         if ( m_str != bstrSrc )
//         {
//             ::SysFreeString( m_str );
//
//             if ( bstrSrc != NULL )
//             {
//                 m_str = ::SysAllocStringByteLen( ( char * )bstrSrc, ::SysStringByteLen( bstrSrc ) );
//
//                 if ( !*this )
//                 {
//                     hr = E_OUTOFMEMORY;
//                 }
//             }
//             else
//             {
//                 m_str = NULL;
//             }
//         }
//
//         return hr;
//     }
//
//     _Check_return_ HRESULT ToLower() throw()
//     {
//         if ( ::SysStringLen( m_str ) > 0 )
//         {
//
//             // Convert in place
//             //just unicode
//             CharLowerBuff( m_str, Length() );
//
//
//         }
//
//         return S_OK;
//     }
//     _Check_return_ HRESULT ToUpper() throw()
//     {
//         if ( ::SysStringLen( m_str ) > 0 )
//         {
//             // Convert in place
// 			//unicode only
//             CharUpperBuff( m_str, Length() );
//
//         }
//
//         return S_OK;
//     }
//
// #ifdef _ATL_USE_WINAPI_FAMILY_DESKTOP_APP
//     bool LoadString(
//         _In_ HINSTANCE hInst,
//         _In_ UINT nID ) throw()
//     {
//         ::SysFreeString( m_str );
//         m_str = NULL;
//         return LoadStringResource( hInst, nID, m_str );
//     }
//
//     bool LoadString( _In_ UINT nID ) throw()
//     {
//         ::SysFreeString( m_str );
//         m_str = NULL;
//         return LoadStringResource( nID, m_str );
//     }
// #endif // _ATL_USE_WINAPI_FAMILY_DESKTOP_APP
//
//     QBstr & operator+=( _In_ const QBstr & bstrSrc )
//     {
//         HRESULT hr;
//         hr = AppendBSTR( bstrSrc.m_str );
//
//         if ( FAILED( hr ) )
//             throw( hr );
//
//         return *this;
//     }
//
//     QBstr & operator+=( _In_z_ LPCOLESTR pszSrc )
//     {
//         HRESULT hr;
//         hr = Append( pszSrc );
//
//         if ( FAILED( hr ) )
//             throw( hr );
//
//         return *this;
//     }
//
//     bool operator<( _In_ const QBstr & bstrSrc ) const throw()
//     {
//         return VarBstrCmp( m_str, bstrSrc.m_str, LOCALE_USER_DEFAULT, 0 ) == static_cast<HRESULT>( VARCMP_LT );
//     }
//     bool operator<( _In_z_ LPCOLESTR pszSrc ) const
//     {
//         QBstr bstr2( pszSrc );
//         return operator<( bstr2 );
//     }
//     bool operator<( _In_z_ LPOLESTR pszSrc ) const
//     {
//         return operator<( ( LPCOLESTR )pszSrc );
//     }
//
//     bool operator>( _In_ const QBstr & bstrSrc ) const throw()
//     {
//         return VarBstrCmp( m_str, bstrSrc.m_str, LOCALE_USER_DEFAULT, 0 ) == static_cast<HRESULT>( VARCMP_GT );
//     }
//     bool operator>( _In_z_ LPCOLESTR pszSrc ) const
//     {
//         QBstr bstr2( pszSrc );
//         return operator>( bstr2 );
//     }
//     bool operator>( _In_z_ LPOLESTR pszSrc ) const
//     {
//         return operator>( ( LPCOLESTR )pszSrc );
//     }
//
//     bool operator!=( _In_ const QBstr & bstrSrc ) const throw()
//     {
//         return !operator==( bstrSrc );
//     }
//     bool operator!=( _In_z_ LPCOLESTR pszSrc ) const
//     {
//         return !operator==( pszSrc );
//     }
//     bool operator!=( _In_ int nNull ) const throw()
//     {
//         return !operator==( nNull );
//     }
//     bool operator!=( _In_z_ LPOLESTR pszSrc ) const
//     {
//         return operator!=( ( LPCOLESTR )pszSrc );
//     }
//     bool operator==( _In_ const QBstr & bstrSrc ) const throw()
//     {
//         return VarBstrCmp( m_str, bstrSrc.m_str, LOCALE_USER_DEFAULT, 0 ) == static_cast<HRESULT>( VARCMP_EQ );
//     }
//     bool operator==( LPCOLESTR pszSrc ) const
//     {
//         QBstr bstr2( pszSrc );
//         return operator==( bstr2 );
//     }
//     bool operator==( _In_z_ LPOLESTR pszSrc ) const
//     {
//         return operator==( ( LPCOLESTR )pszSrc );
//     }
//
//     bool operator==( _In_ int nNull ) const throw()
//     {
//         ASSERT( nNull == 0 );
//         ( void )nNull;
//         return ( !*this );
//     }
//
//     bool operator==( decltype( __nullptr ) ) const throw()
//     {
//         return *this == 0;
//     }
//
//     bool operator!=( decltype( __nullptr ) ) const throw()
//     {
//         return *this != 0;
//     }
//
// //     QBstr( _In_opt_z_ LPCSTR pSrc )
// //     {
// //         if ( pSrc != NULL )
// //         {
// //             m_str = A2WBSTR( pSrc );
// //
// //             if ( !*this )
// //             {
// //                 throw( E_OUTOFMEMORY );
// //             }
// //         }
// //         else
// //         {
// //             m_str = NULL;
// //         }
// //     }
//
// //     QBstr( _In_ int nSize, _In_reads_opt_( nSize ) LPCSTR sz )
// //     {
// //         if ( nSize < 0 )
// //         {
// //             throw( E_INVALIDARG );
// //         }
// //
// //         if ( nSize != 0 && sz == NULL )
// //         {
// //             m_str = ::SysAllocStringLen( NULL, nSize );
// //
// //             if ( !*this )
// //             {
// //                 throw( E_OUTOFMEMORY );
// //             }
// //
// //             return;
// //         }
// //
// //         m_str = A2WBSTR( sz, nSize );
// //
// //         if ( !*this && nSize != 0 )
// //         {
// //             throw( E_OUTOFMEMORY );
// //         }
// //     }
//
// //     _Check_return_ HRESULT Append( _In_opt_z_ LPCSTR lpsz ) throw()
// //     {
// //         if ( lpsz == NULL )
// //             return S_OK;
// //
// //         QBstr bstrTemp;
// //         bstrTemp = lpsz;
// //
// //         if ( !bstrTemp )
// //         {
// //             return E_OUTOFMEMORY;
// //         }
// //
// //         return Append( bstrTemp );
// //     }
//
// //     QBstr & operator=( _In_opt_z_ LPCSTR pSrc )
// //     {
// //         ::SysFreeString( m_str );
// //         m_str = A2WBSTR( pSrc );
// //
// //         if ( !*this && pSrc != NULL )
// //         {
// //             throw( E_OUTOFMEMORY );
// //         }
// //
// //         return *this;
// //     }
//
// //     bool operator<( _In_opt_z_ LPCSTR pszSrc ) const
// //     {
// //         QBstr bstr2( pszSrc );
// //         return operator<( bstr2 );
// //     }
// //     bool operator>( _In_opt_z_ LPCSTR pszSrc ) const
// //     {
// //         QBstr bstr2( pszSrc );
// //         return operator>( bstr2 );
// //     }
// //     bool operator!=( _In_opt_z_ LPCSTR pszSrc ) const
// //     {
// //         return !operator==( pszSrc );
// //     }
// //     bool operator==( _In_opt_z_ LPCSTR pszSrc ) const
// //     {
// //         QBstr bstr2( pszSrc );
// //         return operator==( bstr2 );
// //     }
//
//     _Check_return_ HRESULT WriteToStream( _Inout_ IStream * pStream ) throw()
//     {
//         ASSERT( pStream != NULL );
//
//         if ( pStream == NULL )
//         {
//             return E_INVALIDARG;
//         }
//
//         ULONG cb;
//         ULONG cbStrLen = QBstr::GetStreamSize( m_str );
//         ASSERT( cbStrLen >= sizeof( ULONG ) );
//         cbStrLen -= sizeof( ULONG );
//
//         HRESULT hr = pStream->Write( ( void * ) &cbStrLen, sizeof( cbStrLen ), &cb );
//
//         if ( FAILED( hr ) )
//         {
//             return hr;
//         }
//
//         if ( cbStrLen == 0 )
//         {
//             return S_OK;
//         }
//
//         return pStream->Write( ( void * ) m_str, cbStrLen, &cb );
//     }
//
//     _Check_return_ HRESULT ReadFromStream( _Inout_ IStream * pStream ) throw()
//     {
//         ASSERT( pStream != NULL );
//
//         if ( pStream == NULL )
//         {
//             return E_INVALIDARG;
//         }
//
//         ASSERT( !*this ); // should be empty
//         Empty();
//
//         HRESULT hrSeek;
//         ULARGE_INTEGER nBegOffset;
//         {
//             LARGE_INTEGER nZeroOffset;
//             nZeroOffset.QuadPart = 0L;
//             hrSeek = pStream->Seek( nZeroOffset, STREAM_SEEK_CUR, &nBegOffset );
//         }
//
//         ULONG cbRead = 0;
//         ULONG cbStrLen = 0;
//         HRESULT hr = pStream->Read( reinterpret_cast<void *>( &cbStrLen ), sizeof( cbStrLen ), &cbRead );
//
//         if ( SUCCEEDED( hr ) )
//         {
//             // invalid data size
//             if ( sizeof( cbStrLen ) != cbRead )
//             {
//                 //TRACE( atlTraceCOM, 0, _T( "Input stream is corrupted." ) );
//                 hr = E_FAIL;
//             }
//             // read NULL string
//             else
//                 if ( cbStrLen == 0 )
//                 {
//                 }
//             // invalid data length
//                 else
//                     if ( cbStrLen < sizeof( OLECHAR ) )
//                     {
//                         //TRACE( atlTraceCOM, 0, _T( "Input stream is corrupted." ) );
//                         hr = E_FAIL;
//                     }
//             // security checks when system hang for huge stream of data
//                     else
//                     {
//
//                         //subtract size for terminating NULL which we wrote out
//                         cbStrLen -= sizeof( OLECHAR );
//
//                         m_str = ::SysAllocStringByteLen( NULL, cbStrLen );
//
//                         if ( !*this )
//                         {
//                             hr = E_OUTOFMEMORY;
//                         }
//                         else
//                         {
//                             hr = pStream->Read( reinterpret_cast<void *>( m_str ), cbStrLen, &cbRead );
//
//                             if ( SUCCEEDED( hr ) )
//                             {
//                                 if ( cbRead != cbStrLen )
//                                 {
//                                     //TRACE( atlTraceCOM, 0, _T( "Length of string data is different than expected." ) );
//                                     hr = E_FAIL;
//                                 }
//                                 else
//                                 {
//                                     OLECHAR ch;
//                                     hr = pStream->Read( reinterpret_cast<void *>( &ch ), sizeof( OLECHAR ), &cbRead );
//
//                                     if ( SUCCEEDED( hr ) )
//                                     {
//
//                                         if ( cbRead != sizeof( OLECHAR ) )
//                                         {
//                                             //ATLTRACE( atlTraceCOM, 0, _T( "Cannot read NULL terminator from stream." ) );
//                                             hr = E_FAIL;
//                                         }
//                                     }
//                                 }
//                             }
//
//                             if ( FAILED( hr ) )
//                             {
//                                 ::SysFreeString( m_str );
//                                 m_str = NULL;
//                             }
//                         }
//                     }
//         }
//
//         // If SysAllocStringByteLen or IStream::Read failed, reset seek
//         // pointer to start of BSTR size.
//         if ( FAILED( hr ) && SUCCEEDED( hrSeek ) )
//         {
//             LARGE_INTEGER nOffset;
//             nOffset.QuadPart = static_cast<LONGLONG>( nBegOffset.QuadPart );
//             pStream->Seek( nOffset, STREAM_SEEK_SET, NULL );
//         }
//
//         return hr;
//     }
//
// #ifdef _ATL_USE_WINAPI_FAMILY_DESKTOP_APP
//     _Success_( return != false )
//     static bool LoadStringResource(
//         _In_ HINSTANCE hInstance,
//         _In_ UINT uID,
//         _Inout_ _Pre_null_ _Post_z_ BSTR & bstrText ) throw()
//     {
//         ATLASSERT( bstrText == NULL );
//
//         const ATLSTRINGRESOURCEIMAGE * pImage = AtlGetStringResourceImage( hInstance, uID );
//
//         if ( pImage != NULL )
//         {
//             bstrText = ::SysAllocStringLen( pImage->achString, pImage->nLength );
//         }
//         else
//         {
//             bstrText = NULL;
//         }
//
//         return ( bstrText != NULL ) ? true : false;
//     }
//
//     _Success_( return != false )
//     static bool LoadStringResource(
//         _In_ UINT uID,
//         _Inout_ _Pre_null_ _Post_z_ BSTR & bstrText ) throw()
//     {
//         ATLASSERT( bstrText == NULL );
//
//         const ATLSTRINGRESOURCEIMAGE * pImage = AtlGetStringResourceImage( uID );
//
//         if ( pImage != NULL )
//         {
//             bstrText = ::SysAllocStringLen( pImage->achString, pImage->nLength );
//         }
//         else
//         {
//             bstrText = NULL;
//         }
//
//         return ( bstrText != NULL ) ? true : false;
//     }
//
//     // each character in BSTR is copied to each element in SAFEARRAY
//     HRESULT BSTRToArray( _Outptr_ LPSAFEARRAY * ppArray ) throw()
//     {
//         return VectorFromBstr( m_str, ppArray );
//     }
//
//     // first character of each element in SAFEARRAY is copied to BSTR
//     _Check_return_ HRESULT ArrayToBSTR( _In_ const SAFEARRAY * pSrc ) throw()
//     {
//         ::SysFreeString( m_str );
//         return BstrFromVector( ( LPSAFEARRAY )pSrc, &m_str );
//     }
// #endif // _ATL_USE_WINAPI_FAMILY_DESKTOP_APP
//
//     static ULONG GetStreamSize( _In_opt_z_ BSTR bstr )
//     {
//         ULONG ulSize = sizeof( ULONG );
//
//         if ( bstr != NULL )
//         {
//             ulSize += SysStringByteLen( bstr ) + sizeof( OLECHAR );
//         }
//
//         return ulSize;
//     }
// };
//
// inline QBstr::~QBstr() throw()
// {
//     ::SysFreeString( m_str );
// }
//
// inline void SysFreeStringHelper( _In_ QBstr & bstr )
// {
//     bstr.Empty();
// }
//
// inline void SysFreeStringHelper( _In_opt_z_ BSTR bstr )
// {
//     ::SysFreeString( bstr );
// }
//
// _Check_return_ inline HRESULT SysAllocStringHelper(
//     _Out_ QBstr & bstrDest,
//     _In_opt_z_ BSTR bstrSrc )
// {
//     bstrDest = bstrSrc;
//     return !bstrDest ? E_OUTOFMEMORY : S_OK;
// }
//
// _Check_return_ inline HRESULT SysAllocStringHelper(
//     _Out_ BSTR & bstrDest,
//     _In_opt_z_ BSTR bstrSrc )
// {
//     bstrDest =::SysAllocString( bstrSrc );
//
//     return bstrDest == NULL ? E_OUTOFMEMORY : S_OK;
// }


//////////////////////////////////////////////////////////////////////////

// class QComVariant : public tagVARIANT
// {
//     // Constructors
// public:
//     QComVariant() throw()
//     {
//         // Make sure that variant data are initialized to 0
//         memset( this, 0, sizeof( tagVARIANT ) );
//         ::VariantInit( this );
//     }
//     ~QComVariant() throw()
//     {
//         HRESULT hr = Clear();
//         ASSERT( SUCCEEDED( hr ) );
//         ( hr );
//     }
//     QComVariant( _In_ const VARIANT & varSrc )
//     {
//         vt = VT_EMPTY;
//         InternalCopy( &varSrc );
//     }
//     QComVariant( _In_ const QComVariant & varSrc )
//     {
//         vt = VT_EMPTY;
//         InternalCopy( &varSrc );
//     }
//     QComVariant( _In_z_ LPCOLESTR lpszSrc )
//     {
//         vt = VT_EMPTY;
//         *this = lpszSrc;
//     }
// //     QComVariant( _In_z_ LPCSTR lpszSrc )
// //     {
// //         vt = VT_EMPTY;
// //         *this = lpszSrc;
// //     }
//     QComVariant( _In_ bool bSrc ) throw()
//     {
//         vt = VT_BOOL;
//         boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE;
//     }
//
//     QComVariant( _In_ int nSrc, _In_ VARTYPE vtSrc = VT_I4 )
//     {
//         ASSERT( vtSrc == VT_I4 || vtSrc == VT_INT );
//
//         if ( vtSrc == VT_I4 || vtSrc == VT_INT )
//         {
//             vt = vtSrc;
//             intVal = nSrc;
//         }
//         else
//         {
//             vt = VT_ERROR;
//             scode = E_INVALIDARG;
//
//             throw( E_INVALIDARG );
//
//         }
//     }
//
//     QComVariant( _In_ BYTE nSrc ) throw()
//     {
//         vt = VT_UI1;
//         bVal = nSrc;
//     }
//     QComVariant( _In_ short nSrc ) throw()
//     {
//         vt = VT_I2;
//         iVal = nSrc;
//     }
//     QComVariant( _In_ long nSrc, _In_ VARTYPE vtSrc = VT_I4 )
//     {
//         ASSERT( vtSrc == VT_I4 || vtSrc == VT_ERROR );
//
//         if ( vtSrc == VT_I4 || vtSrc == VT_ERROR )
//         {
//             vt = vtSrc;
//             lVal = nSrc;
//         }
//         else
//         {
//             vt = VT_ERROR;
//             scode = E_INVALIDARG;
//
//             throw( E_INVALIDARG );
//
//         }
//     }
//
//     QComVariant( _In_ float fltSrc ) throw()
//     {
//         vt = VT_R4;
//         fltVal = fltSrc;
//     }
//     QComVariant( _In_ double dblSrc, _In_ VARTYPE vtSrc = VT_R8 )
//     {
//         ASSERT( vtSrc == VT_R8 || vtSrc == VT_DATE );
//
//         if ( vtSrc == VT_R8 || vtSrc == VT_DATE )
//         {
//             vt = vtSrc;
//             dblVal = dblSrc;
//         }
//         else
//         {
//             vt = VT_ERROR;
//             scode = E_INVALIDARG;
//
//             throw( E_INVALIDARG );
//
//         }
//     }
//
// #if (_WIN32_WINNT >= 0x0501)
//     QComVariant( _In_ LONGLONG nSrc ) throw()
//     {
//         vt = VT_I8;
//         llVal = nSrc;
//     }
//     QComVariant( _In_ ULONGLONG nSrc ) throw()
//     {
//         vt = VT_UI8;
//         ullVal = nSrc;
//     }
// #endif
//     QComVariant( _In_ CY cySrc ) throw()
//     {
//         vt = VT_CY;
//         cyVal.Hi = cySrc.Hi;
//         cyVal.Lo = cySrc.Lo;
//     }
//     QComVariant( _In_opt_ IDispatch * pSrc ) throw()
//     {
//         vt = VT_DISPATCH;
//         pdispVal = pSrc;
//
//         // Need to AddRef as VariantClear will Release
//         if ( pdispVal != nullptr )
//             pdispVal->AddRef();
//     }
//     QComVariant( _In_opt_ IUnknown * pSrc ) throw()
//     {
//         vt = VT_UNKNOWN;
//         punkVal = pSrc;
//
//         // Need to AddRef as VariantClear will Release
//         if ( punkVal != nullptr )
//             punkVal->AddRef();
//     }
//     QComVariant( _In_ char cSrc ) throw()
//     {
//         vt = VT_I1;
//         cVal = cSrc;
//     }
//     QComVariant( _In_ unsigned short nSrc ) throw()
//     {
//         vt = VT_UI2;
//         uiVal = nSrc;
//     }
//     QComVariant( _In_ unsigned long nSrc ) throw()
//     {
//         vt = VT_UI4;
//         ulVal = nSrc;
//     }
//     QComVariant( _In_ unsigned int nSrc, _In_ VARTYPE vtSrc = VT_UI4 )
//     {
//         ASSERT( vtSrc == VT_UI4 || vtSrc == VT_UINT );
//
//         if ( vtSrc == VT_UI4 || vtSrc == VT_UINT )
//         {
//             vt = vtSrc;
//             uintVal = nSrc;
//         }
//         else
//         {
//             vt = VT_ERROR;
//             scode = E_INVALIDARG;
//
//             throw( E_INVALIDARG );
//
//         }
//     }
//     QComVariant( _In_ const BSTR & bstrSrc )
//     {
//         vt = VT_EMPTY;
//         *this = bstrSrc;
//     }
//     QComVariant( _In_ const SAFEARRAY * pSrc );
//
//     // Assignment Operators
// public:
//     QComVariant & operator=( _In_ const QComVariant & varSrc )
//     {
//         if ( this != &varSrc )
//         {
//             InternalCopy( &varSrc );
//         }
//
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ const VARIANT & varSrc )
//     {
//         if ( static_cast<VARIANT *>( this ) != &varSrc )
//         {
//             InternalCopy( &varSrc );
//         }
//
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ const QBstr & bstrSrc )
//     {
//         ClearThrow();
//
//         vt = VT_BSTR;
//         bstrVal = bstrSrc.Copy();
//
//         if ( bstrVal == nullptr && bstrSrc.m_str != nullptr )
//         {
//             vt = VT_ERROR;
//             scode = E_OUTOFMEMORY;
//
//             throw( E_OUTOFMEMORY );
//
//         }
//
//         return *this;
//     }
//
//     QComVariant & operator=( _In_z_ LPCOLESTR lpszSrc )
//     {
//         if ( vt != VT_BSTR || bstrVal != lpszSrc )
//         {
//             ClearThrow();
//
//             vt = VT_BSTR;
//             bstrVal = ::SysAllocString( lpszSrc );
//
//             if ( bstrVal == nullptr && lpszSrc != nullptr )
//             {
//                 vt = VT_ERROR;
//                 scode = E_OUTOFMEMORY;
//
//                 throw( E_OUTOFMEMORY );
//
//             }
//         }
//
//         return *this;
//     }
//
// //     QComVariant & operator=( _In_z_ LPCSTR lpszSrc )
// //     {
// //         USES_CONVERSION_EX;
// //         ClearThrow();
// //
// //         vt = VT_BSTR;
// //         bstrVal = ::SysAllocString( A2COLE_EX( lpszSrc, _ATL_SAFE_ALLOCA_DEF_THRESHOLD ) );
// //
// //         if ( bstrVal == nullptr && lpszSrc != nullptr )
// //         {
// //             vt = VT_ERROR;
// //             scode = E_OUTOFMEMORY;
// //
// //             throw( E_OUTOFMEMORY );
// //
// //         }
// //
// //         return *this;
// //     }
//
//     QComVariant & operator=( _In_ bool bSrc )
//     {
//         if ( vt != VT_BOOL )
//         {
//             ClearThrow();
//             vt = VT_BOOL;
//         }
//
//         boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ int nSrc )
//     {
//         if ( vt != VT_I4 )
//         {
//             ClearThrow();
//             vt = VT_I4;
//         }
//
//         intVal = nSrc;
//
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ BYTE nSrc )
//     {
//         if ( vt != VT_UI1 )
//         {
//             ClearThrow();
//             vt = VT_UI1;
//         }
//
//         bVal = nSrc;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ short nSrc )
//     {
//         if ( vt != VT_I2 )
//         {
//             ClearThrow();
//             vt = VT_I2;
//         }
//
//         iVal = nSrc;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ long nSrc )
//     {
//         if ( vt != VT_I4 )
//         {
//             ClearThrow();
//             vt = VT_I4;
//         }
//
//         lVal = nSrc;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ float fltSrc )
//     {
//         if ( vt != VT_R4 )
//         {
//             ClearThrow();
//             vt = VT_R4;
//         }
//
//         fltVal = fltSrc;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ double dblSrc )
//     {
//         if ( vt != VT_R8 )
//         {
//             ClearThrow();
//             vt = VT_R8;
//         }
//
//         dblVal = dblSrc;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ CY cySrc )
//     {
//         if ( vt != VT_CY )
//         {
//             ClearThrow();
//             vt = VT_CY;
//         }
//
//         cyVal.Hi = cySrc.Hi;
//         cyVal.Lo = cySrc.Lo;
//         return *this;
//     }
//
//     QComVariant & operator=( _Inout_opt_ IDispatch * pSrc )
//     {
//         if ( vt != VT_DISPATCH || pSrc != pdispVal )
//         {
//             ClearThrow();
//
//             vt = VT_DISPATCH;
//             pdispVal = pSrc;
//
//             // Need to AddRef as VariantClear will Release
//             if ( pdispVal != nullptr )
//                 pdispVal->AddRef();
//         }
//
//         return *this;
//     }
//
//     QComVariant & operator=( _Inout_opt_ IUnknown * pSrc )
//     {
//         if ( vt != VT_UNKNOWN || pSrc != punkVal )
//         {
//             ClearThrow();
//
//             vt = VT_UNKNOWN;
//             punkVal = pSrc;
//
//             // Need to AddRef as VariantClear will Release
//             if ( punkVal != nullptr )
//                 punkVal->AddRef();
//         }
//
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ char cSrc )
//     {
//         if ( vt != VT_I1 )
//         {
//             ClearThrow();
//             vt = VT_I1;
//         }
//
//         cVal = cSrc;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ unsigned short nSrc )
//     {
//         if ( vt != VT_UI2 )
//         {
//             ClearThrow();
//             vt = VT_UI2;
//         }
//
//         uiVal = nSrc;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ unsigned long nSrc )
//     {
//         if ( vt != VT_UI4 )
//         {
//             ClearThrow();
//             vt = VT_UI4;
//         }
//
//         ulVal = nSrc;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ unsigned int nSrc )
//     {
//         if ( vt != VT_UI4 )
//         {
//             ClearThrow();
//             vt = VT_UI4;
//         }
//
//         uintVal = nSrc;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ BYTE * pbSrc )
//     {
//         if ( vt != ( VT_UI1 | VT_BYREF ) )
//         {
//             ClearThrow();
//             vt = VT_UI1 | VT_BYREF;
//         }
//
//         pbVal = pbSrc;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ short * pnSrc )
//     {
//         if ( vt != ( VT_I2 | VT_BYREF ) )
//         {
//             ClearThrow();
//             vt = VT_I2 | VT_BYREF;
//         }
//
//         piVal = pnSrc;
//         return *this;
//     }
//
// #ifdef _NATIVE_WCHAR_T_DEFINED
//     QComVariant & operator=( _In_ USHORT * pnSrc )
//     {
//         if ( vt != ( VT_UI2 | VT_BYREF ) )
//         {
//             ClearThrow();
//             vt = VT_UI2 | VT_BYREF;
//         }
//
//         puiVal = pnSrc;
//         return *this;
//     }
// #endif
//
//     QComVariant & operator=( _In_ int * pnSrc )
//     {
//         if ( vt != ( VT_I4 | VT_BYREF ) )
//         {
//             ClearThrow();
//             vt = VT_I4 | VT_BYREF;
//         }
//
//         pintVal = pnSrc;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ UINT * pnSrc )
//     {
//         if ( vt != ( VT_UI4 | VT_BYREF ) )
//         {
//             ClearThrow();
//             vt = VT_UI4 | VT_BYREF;
//         }
//
//         puintVal = pnSrc;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ long * pnSrc )
//     {
//         if ( vt != ( VT_I4 | VT_BYREF ) )
//         {
//             ClearThrow();
//             vt = VT_I4 | VT_BYREF;
//         }
//
//         plVal = pnSrc;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ ULONG * pnSrc )
//     {
//         if ( vt != ( VT_UI4 | VT_BYREF ) )
//         {
//             ClearThrow();
//             vt = VT_UI4 | VT_BYREF;
//         }
//
//         pulVal = pnSrc;
//         return *this;
//     }
//
// #if (_WIN32_WINNT >= 0x0501)
//     QComVariant & operator=( _In_ LONGLONG nSrc )
//     {
//         if ( vt != VT_I8 )
//         {
//             ClearThrow();
//             vt = VT_I8;
//         }
//
//         llVal = nSrc;
//
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ LONGLONG * pnSrc )
//     {
//         if ( vt != ( VT_I8 | VT_BYREF ) )
//         {
//             ClearThrow();
//             vt = VT_I8 | VT_BYREF;
//         }
//
//         pllVal = pnSrc;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ ULONGLONG nSrc )
//     {
//         if ( vt != VT_UI8 )
//         {
//             ClearThrow();
//             vt = VT_UI8;
//         }
//
//         ullVal = nSrc;
//
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ ULONGLONG * pnSrc )
//     {
//         if ( vt != ( VT_UI8 | VT_BYREF ) )
//         {
//             ClearThrow();
//             vt = VT_UI8 | VT_BYREF;
//         }
//
//         pullVal = pnSrc;
//         return *this;
//     }
// #endif
//
//     QComVariant & operator=( _In_ float * pfSrc )
//     {
//         if ( vt != ( VT_R4 | VT_BYREF ) )
//         {
//             ClearThrow();
//             vt = VT_R4 | VT_BYREF;
//         }
//
//         pfltVal = pfSrc;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ double * pfSrc )
//     {
//         if ( vt != ( VT_R8 | VT_BYREF ) )
//         {
//             ClearThrow();
//             vt = VT_R8 | VT_BYREF;
//         }
//
//         pdblVal = pfSrc;
//         return *this;
//     }
//
//     QComVariant & operator=( _In_ const SAFEARRAY * pSrc );
//
//
//     // Comparison Operators
// public:
//     bool operator==( _In_ const VARIANT & varSrc ) const throw()
//     {
//         // For backwards compatibility
//         if ( vt == VT_NULL && varSrc.vt == VT_NULL )
//         {
//             return true;
//         }
//
//         // Variants not equal if types don't match
//         if ( vt != varSrc.vt )
//         {
//             return false;
//         }
//
//         return VarCmp( ( VARIANT * )this, ( VARIANT * )&varSrc, LOCALE_USER_DEFAULT, 0 ) == static_cast<HRESULT>( VARCMP_EQ );
//     }
//
//     bool operator!=( _In_ const VARIANT & varSrc ) const throw()
//     {
//         return !operator==( varSrc );
//     }
//
//     bool operator<( _In_ const VARIANT & varSrc ) const throw()
//     {
//         if ( vt == VT_NULL && varSrc.vt == VT_NULL )
//             return false;
//
//         return VarCmp( ( VARIANT * )this, ( VARIANT * )&varSrc, LOCALE_USER_DEFAULT, 0 ) == static_cast<HRESULT>( VARCMP_LT );
//     }
//
//     bool operator>( _In_ const VARIANT & varSrc ) const throw()
//     {
//         if ( vt == VT_NULL && varSrc.vt == VT_NULL )
//             return false;
//
//         return VarCmp( ( VARIANT * )this, ( VARIANT * )&varSrc, LOCALE_USER_DEFAULT, 0 ) == static_cast<HRESULT>( VARCMP_GT );
//     }
//
// private:
//     inline HRESULT VarCmp(
//         _In_ LPVARIANT pvarLeft,
//         _In_ LPVARIANT pvarRight,
//         _In_ LCID lcid,
//         _In_ ULONG dwFlags ) const throw();
//
//     // Operations
// public:
//     HRESULT Clear()
//     {
//         return ::VariantClear( this );
//     }
//     HRESULT Copy( _In_ const VARIANT * pSrc )
//     {
//         return ::VariantCopy( this, const_cast<VARIANT *>( pSrc ) );
//     }
//
//     // copy VARIANT to BSTR
//     HRESULT CopyTo( _Outptr_result_z_ BSTR * pstrDest ) const
//     {
//         ASSERT( pstrDest != nullptr && vt == VT_BSTR );
//         HRESULT hRes = E_POINTER;
//
//         if ( pstrDest != nullptr && vt == VT_BSTR )
//         {
//             *pstrDest = ::SysAllocStringByteLen( ( char * )bstrVal, ::SysStringByteLen( bstrVal ) );
//
//             if ( *pstrDest == nullptr )
//                 hRes = E_OUTOFMEMORY;
//             else
//                 hRes = S_OK;
//         }
//         else
//             if ( vt != VT_BSTR )
//                 hRes = DISP_E_TYPEMISMATCH;
//
//         return hRes;
//     }
//
//     HRESULT Attach( _In_ VARIANT * pSrc )
//     {
//         if ( pSrc == nullptr )
//             return E_INVALIDARG;
//
//         HRESULT hr = S_OK;
//
//         if ( this != pSrc )
//         {
//             // Clear out the variant
//             hr = Clear();
//
//             if ( SUCCEEDED( hr ) )
//             {
//                 // Copy the contents and give control to QComVariant
//                 memcpy_s( this, sizeof( QComVariant ), pSrc, sizeof( VARIANT ) );
//                 pSrc->vt = VT_EMPTY;
//                 hr = S_OK;
//             }
//         }
//
//         return hr;
//     }
//
//     HRESULT Detach( _Inout_ VARIANT * pDest )
//     {
//         ASSERT( pDest != nullptr );
//
//         if ( pDest == nullptr )
//             return E_POINTER;
//
//         // Clear out the variant
//         HRESULT hr = ::VariantClear( pDest );
//
//         if ( SUCCEEDED( hr ) )
//         {
//             // Copy the contents and remove control from QComVariant
//             memcpy_s( pDest, sizeof( VARIANT ), this, sizeof( VARIANT ) );
//             vt = VT_EMPTY;
//             hr = S_OK;
//         }
//
//         return hr;
//     }
//
//     HRESULT ChangeType( _In_ VARTYPE vtNew, _In_opt_ const VARIANT * pSrc = nullptr )
//     {
//         VARIANT * pVar = const_cast<VARIANT *>( pSrc );
//
//         // Convert in place if pSrc is nullptr
//         if ( pVar == nullptr )
//             pVar = this;
//
//         // Do nothing if doing in place convert and vts not different
//         return ::VariantChangeType( this, pVar, 0, vtNew );
//     }
//
//     template< typename T >
//     void SetByRef( _In_ T * pT )
//     {
//         ClearThrow();
//         vt = CVarTypeInfo< T * >::VT;
//         byref = pT;
//     }
//
// #ifdef _ATL_USE_WINAPI_FAMILY_DESKTOP_APP
//     _Check_return_ HRESULT WriteToStream( _Inout_ IStream * pStream );
//     _Check_return_ HRESULT WriteToStream(
//         _Inout_ IStream * pStream,
//         _In_ VARTYPE vtWrite )
//     {
//         if ( vtWrite != VT_EMPTY && vtWrite != vt )
//         {
//             QComVariant varConv;
//             HRESULT hr = varConv.ChangeType( vtWrite, this );
//
//             if ( FAILED( hr ) )
//             {
//                 return hr;
//             }
//
//             return varConv.WriteToStream( pStream );
//         }
//
//         return WriteToStream( pStream );
//     }
//
//     _Check_return_ HRESULT ReadFromStream(
//         _Inout_ IStream * pStream,
//         _In_ VARTYPE vtExpected = VT_EMPTY );
//
//     _Check_return_ HRESULT ReadFromStream(
//         _Inout_ IStream * pStream,
//         _In_ VARTYPE vtExpected,
//         _In_ ClassesAllowedInStream rgclsidAllowed,
//         _In_ DWORD cclsidAllowed );
//
//     // Return the size in bytes of the current contents
//     ULONG GetSize() const;
//     HRESULT GetSizeMax( _Out_ ULARGE_INTEGER * pcbSize ) const;
// #endif // _ATL_USE_WINAPI_FAMILY_DESKTOP_APP
//
//     // Implementation
// private:
//     void ClearThrow()
//     {
//         HRESULT hr = Clear();
//         ASSERT( SUCCEEDED( hr ) );
//         ( hr );
//
//
//         if ( FAILED( hr ) )
//         {
//             throw( hr );
//         }
//     }
//
// public:
//     _Check_return_ HRESULT InternalClear()
//     {
//         HRESULT hr = Clear();
//         ASSERT( SUCCEEDED( hr ) );
//
//         if ( FAILED( hr ) )
//         {
//             vt = VT_ERROR;
//             scode = hr;
//
//             throw( hr );
//         }
//
//         return hr;
//     }
//
//     void InternalCopy( _In_ const VARIANT * pSrc )
//     {
//         HRESULT hr = Copy( pSrc );
//
//         if ( FAILED( hr ) )
//         {
//             vt = VT_ERROR;
//             scode = hr;
//
//             throw( hr );
//         }
//     }
// };
//

}
}//micro